﻿using EShop.Net.IRepository;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace EShop.Net.Repository
{
    /// <summary>
    /// 仓储通用接口类  实现
    /// 只提供了基础的增删改查，涉及复杂增删改查，请在仓储层写相关方法
    /// </summary>
    /// <typeparam name="T">泛型实体类</typeparam>
    public abstract class BaseRepository<T> : IBaseRepository<T> where T : class, new()
    {
        /// <summary>
        /// SqlSugarScope 是基于 SqlSugarClient 基础上实现了线程安全机制
        /// </summary>
        private readonly SqlSugarScope _dbBase;

        protected BaseRepository(UnitOfWork.UnitOfWork unitOfWork)
        {
            this._dbBase = unitOfWork.GetDbClient();
        }

        private ISqlSugarClient DbBaseClient => _dbBase;

        protected ISqlSugarClient DbClient => DbBaseClient;

        /// <summary>
        /// 根据ID，查询单条数据(同步)
        /// </summary>
        /// <param name="pkValue">ID</param>
        /// <returns>数据实体</returns>
        public T QueryById(object pkValue)
        {
            return DbBaseClient.Queryable<T>().InSingle(pkValue);
        }

        /// <summary>
        /// 根据ID，查询单条数据(异步)
        /// </summary>
        /// <param name="objId">ID（必须指定主键特性 [SugarColumn(IsPrimaryKey=true)]），如果是联合主键，请使用Where条件</param>
        /// <returns>数据实体</returns>
        public async Task<T> QueryByIdAsync(object objId)
        {
            return await DbBaseClient.Queryable<T>().In(objId).SingleAsync();
        }

        /// <summary>
        /// 查询所有数据，无分页小小使用(同步)
        /// </summary>
        /// <param name="blUseNoLock">是否使用WITH(NOLOCK)</param>
        /// <returns></returns>
        public List<T> Query(bool blUseNoLock = false)
        {
            return blUseNoLock
                ? DbBaseClient.Queryable<T>().With(SqlWith.NoLock).ToList()
                : DbBaseClient.Queryable<T>().ToList();
        }

        /// <summary>
        /// 查询所有数据，无分页小小使用(异步)
        /// </summary>
        /// <param name="blUseNoLock">是否使用WITH(NOLOCK)</param>
        /// <returns></returns>
        public async Task<List<T>> QueryAsync(bool blUseNoLock = false)
        {
            return blUseNoLock
                ? await DbBaseClient.Queryable<T>().With(SqlWith.NoLock).ToListAsync()
                : await DbBaseClient.Queryable<T>().ToListAsync();
        }

        /// <summary>
        /// 根据条件查询数据(同步)
        /// </summary>
        /// <param name="predicate">条件表达式树</param>
        /// <param name="orderBy">排序字段，如name asc,age desc</param>
        /// <returns>泛型实体集合</returns>
        public List<T> QueryListByClause(Expression<Func<T, bool>> predicate, string orderBy = "")
        {
            return DbBaseClient.Queryable<T>().OrderByIF(!string.IsNullOrEmpty(orderBy), orderBy)
                    .WhereIF(predicate != null, predicate).ToList();
        }

        /// <summary>
        /// 根据条件查询数据(异步)
        /// </summary>
        /// <param name="predicate">条件表达式树</param>
        /// <param name="orderBy">排序</param>
        /// <returns>泛型实体集合</returns>
        public async Task<List<T>> QueryListByClauseAsync(Expression<Func<T, bool>> predicate, string orderBy = "")
        {
            return await DbBaseClient.Queryable<T>().OrderByIF(!string.IsNullOrEmpty(orderBy), orderBy)
                    .WhereIF(predicate != null, predicate).ToListAsync();
        }

        /// <summary>
        /// 写入实体数据(同步)
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <returns>受影响行数</returns>
        public int Insert(T entity)
        {
            return DbBaseClient.Insertable(entity).ExecuteReturnIdentity();
        }

        /// <summary>
        /// 写入实体数据(异步)
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <returns>受影响行数</returns>
        public async Task<int> InsertAsync(T entity)
        {
            return await DbBaseClient.Insertable(entity).ExecuteReturnIdentityAsync();
        }

        /// <summary>
        /// 更新实体数据(同步)
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <returns>成功或失败</returns>
        public bool Update(T entity)
        {
            return DbBaseClient.Updateable(entity).ExecuteCommandHasChange();
        }

        /// <summary>
        /// 更新实体数据(异步)
        /// </summary>
        /// <param name="entity">实体数据</param>
        /// <returns>成功或失败</returns>
        public async Task<bool> UpdateAsync(T entity)
        {
            return await DbBaseClient.Updateable(entity).ExecuteCommandHasChangeAsync();
        }

        /// <summary>
        /// 删除指定ID的数据(同步)
        /// </summary>
        /// <param name="id">ID</param>
        /// <returns>成功或失败</returns>
        public bool DeleteById(object id)
        {
            return DbBaseClient.Deleteable<T>(id).ExecuteCommandHasChange();
        }

        /// <summary>
        /// 删除指定ID的数据(异步)
        /// </summary>
        /// <param name="id">ID</param>
        /// <returns>成功或失败</returns>
        public async Task<bool> DeleteByIdAsync(object id)
        {
            return await DbBaseClient.Deleteable<T>(id).ExecuteCommandHasChangeAsync();
        }

        /// <summary>
        /// 执行预处理sql语句并返回List<T>
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <param name="parameters">预处理对象</param>
        /// <returns></returns>
        public List<T> SqlQueryPara(string sql, List<SugarParameter> parameters)
        {
            var list = DbBaseClient.Ado.SqlQuery<T>(sql, parameters);
            return list;
        }

        /// <summary>
        /// 执行sql语句并返回List<T>
        /// </summary>
        /// <param name="sql">SQL语句</param>
        /// <returns></returns>
        public async Task<List<T>> SqlQuery(string sql)
        {
            var list = await DbBaseClient.SqlQueryable<T>(sql).ToListAsync();
            return list;
        }
    }
}
